]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
components: Drop telepathy client
authorJulian Sparber <julian@sparber.net>
Fri, 9 Feb 2024 19:08:25 +0000 (20:08 +0100)
committerFlorian Müllner <fmuellner@gnome.org>
Sun, 3 Mar 2024 01:33:16 +0000 (01:33 +0000)
The telepathy client component has been unmaintained for a long time.
Now that we rework the notifications massively it's time to drop the
support for it.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/3173>

data/theme/gnome-shell-sass/widgets/_notifications.scss
js/js-resources.gresource.xml
js/misc/dependencies.js
js/ui/components/telepathyClient.js [deleted file]
js/ui/messageTray.js
js/ui/sessionMode.js
po/POTFILES.in

index 9b358cfaac0aceb3daea9d2697868c329fc9eb85..a5497e20f0e3b8ddfe9598bbff4a40446f88aa3c 100644 (file)
@@ -23,42 +23,3 @@ $notification_banner_width: 34em;
     @extend %bubble_button;
   }
 }
-
-// counter
-.summary-source-counter {
-  font-size: $base_font_size - 1pt;
-  font-weight: bold;
-  height: 1.6em;
-  width: 1.6em;
-  -shell-counter-overlap-x: 3px;
-  -shell-counter-overlap-y: 3px;
-  background-color: $selected_bg_color;
-  color: $selected_fg_color;
-  border: 2px solid $fg_color;
-  box-shadow: 0 2px 2px rgba(0,0,0,0.5);
-  border-radius: 0.9em; // should be 0.8 but whatever; wish I could do 50%;
-}
-
-// chat bubbles
-.chat-body { spacing: 5px; }
-.chat-response { margin: 5px; }
-.chat-log-message { color: darken($fg_color,10%); }
-.chat-new-group { padding-top: 1em; }
-.chat-received {
-  padding-left: 4px;
-  &:rtl { padding-left: 0px; padding-right: 4px; }
-}
-
-.chat-sent {
-  padding-left: 18pt;
-  color: lighten($fg_color, 15%);
-  &:rtl { padding-left: 0; padding-right: 18pt; }
-}
-
-.chat-meta-message {
-  @extend %caption;
-  padding-left: 4px;
-  font-weight: bold;
-  color: lighten($fg_color,18%);
-  &:rtl { padding-left: 0; padding-right: 4px; }
-}
index ad83acc30c7e691b5896622aae51d5f465c0ab83..fda48d3989004452d7cb3a43036a057c110d5ca5 100644 (file)
     <file>ui/components/keyring.js</file>
     <file>ui/components/networkAgent.js</file>
     <file>ui/components/polkitAgent.js</file>
-    <file>ui/components/telepathyClient.js</file>
 
     <file>ui/status/accessibility.js</file>
     <file>ui/status/autoRotate.js</file>
index c61753e651cd32d0899117c3a649d6ac62dc982f..d4837af04a6d2495ca3ffeac0379cd1592b6b842 100644 (file)
@@ -63,12 +63,3 @@ try {
 } catch {
     console.debug('Malcontent is not available, parental controls integration will be disabled.');
 }
-
-
-try {
-    // Telepathy is optional, so catch any errors loading it
-    gi.require('TelepathyGLib', '0.12');
-    gi.require('TelepathyLogger', '0.2');
-} catch {
-    console.debug('Telepathy is not available, chat integration will be disabled.');
-}
diff --git a/js/ui/components/telepathyClient.js b/js/ui/components/telepathyClient.js
deleted file mode 100644 (file)
index 9f1fa48..0000000
+++ /dev/null
@@ -1,982 +0,0 @@
-// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
-import Clutter from 'gi://Clutter';
-import Gio from 'gi://Gio';
-import GLib from 'gi://GLib';
-import GObject from 'gi://GObject';
-import St from 'gi://St';
-
-let Tpl = null;
-let Tp = null;
-try {
-    ({default: Tp} = await import('gi://TelepathyGlib'));
-    ({default: Tpl} = await import('gi://TelepathyLogger'));
-
-    Gio._promisify(Tp.Channel.prototype, 'close_async');
-    Gio._promisify(Tp.TextChannel.prototype, 'send_message_async');
-    Gio._promisify(Tp.ChannelDispatchOperation.prototype, 'claim_with_async');
-    Gio._promisify(Tpl.LogManager.prototype, 'get_filtered_events_async');
-} catch {
-    console.debug('Skipping chat support, telepathy not found');
-}
-
-import * as History from '../../misc/history.js';
-import * as Main from '../main.js';
-import * as MessageList from '../messageList.js';
-import * as MessageTray from '../messageTray.js';
-import * as Params from '../../misc/params.js';
-import * as Util from '../../misc/util.js';
-
-const HAVE_TP = Tp != null && Tpl != null;
-
-// See Notification.appendMessage
-const SCROLLBACK_IMMEDIATE_TIME = 3 * 60; // 3 minutes
-const SCROLLBACK_RECENT_TIME = 15 * 60; // 15 minutes
-const SCROLLBACK_RECENT_LENGTH = 20;
-const SCROLLBACK_IDLE_LENGTH = 5;
-
-// See Source._displayPendingMessages
-const SCROLLBACK_HISTORY_LINES = 10;
-
-// See Notification._onEntryChanged
-const COMPOSING_STOP_TIMEOUT = 5;
-
-const CHAT_EXPAND_LINES = 12;
-
-const NotificationDirection = {
-    SENT: 'chat-sent',
-    RECEIVED: 'chat-received',
-};
-
-const ChatMessage = HAVE_TP ? GObject.registerClass({
-    Properties: {
-        'message-type': GObject.ParamSpec.int(
-            'message-type', 'message-type', 'message-type',
-            GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
-            Math.min(...Object.values(Tp.ChannelTextMessageType)),
-            Math.max(...Object.values(Tp.ChannelTextMessageType)),
-            Tp.ChannelTextMessageType.NORMAL),
-        'text': GObject.ParamSpec.string(
-            'text', 'text', 'text',
-            GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
-            null),
-        'sender': GObject.ParamSpec.string(
-            'sender', 'sender', 'sender',
-            GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
-            null),
-        'timestamp': GObject.ParamSpec.int64(
-            'timestamp', 'timestamp', 'timestamp',
-            GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
-            0, Number.MAX_SAFE_INTEGER, 0),
-        'direction': GObject.ParamSpec.string(
-            'direction', 'direction', 'direction',
-            GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
-            null),
-    },
-}, class ChatMessageClass extends GObject.Object {
-    static newFromTpMessage(tpMessage, direction) {
-        return new ChatMessage({
-            'message-type': tpMessage.get_message_type(),
-            'text': tpMessage.to_text()[0],
-            'sender': tpMessage.sender.alias,
-            'timestamp': direction === NotificationDirection.RECEIVED
-                ? tpMessage.get_received_timestamp() : tpMessage.get_sent_timestamp(),
-            direction,
-        });
-    }
-
-    static newFromTplTextEvent(tplTextEvent) {
-        let direction =
-            tplTextEvent.get_sender().get_entity_type() === Tpl.EntityType.SELF
-                ? NotificationDirection.SENT : NotificationDirection.RECEIVED;
-
-        return new ChatMessage({
-            'message-type': tplTextEvent.get_message_type(),
-            'text': tplTextEvent.get_message(),
-            'sender': tplTextEvent.get_sender().get_alias(),
-            'timestamp': tplTextEvent.get_timestamp(),
-            direction,
-        });
-    }
-}) : null;
-
-
-class TelepathyComponent {
-    constructor() {
-        this._client = null;
-
-        if (!HAVE_TP)
-            return; // Telepathy isn't available
-
-        this._client = new TelepathyClient();
-    }
-
-    enable() {
-        if (!this._client)
-            return;
-
-        try {
-            this._client.register();
-        } catch (e) {
-            throw new Error(`Could not register Telepathy client. Error: ${e}`);
-        }
-
-        if (!this._client.account_manager.is_prepared(Tp.AccountManager.get_feature_quark_core()))
-            this._client.account_manager.prepare_async(null, null);
-    }
-
-    disable() {
-        if (!this._client)
-            return;
-
-        this._client.unregister();
-    }
-}
-
-const TelepathyClient = HAVE_TP ? GObject.registerClass(
-class TelepathyClient extends Tp.BaseClient {
-    _init() {
-        // channel path -> ChatSource
-        this._chatSources = {};
-        this._chatState = Tp.ChannelChatState.ACTIVE;
-
-        // account path -> AccountNotification
-        this._accountNotifications = {};
-
-        // Define features we want
-        this._accountManager = Tp.AccountManager.dup();
-        let factory = this._accountManager.get_factory();
-        factory.add_account_features([Tp.Account.get_feature_quark_connection()]);
-        factory.add_connection_features([Tp.Connection.get_feature_quark_contact_list()]);
-        factory.add_channel_features([Tp.Channel.get_feature_quark_contacts()]);
-        factory.add_contact_features([
-            Tp.ContactFeature.ALIAS,
-            Tp.ContactFeature.AVATAR_DATA,
-            Tp.ContactFeature.PRESENCE,
-            Tp.ContactFeature.SUBSCRIPTION_STATES,
-        ]);
-
-        // Set up a SimpleObserver, which will call _observeChannels whenever a
-        // channel matching its filters is detected.
-        // The second argument, recover, means _observeChannels will be run
-        // for any existing channel as well.
-        super._init({
-            name: 'GnomeShell',
-            account_manager: this._accountManager,
-            uniquify_name: true,
-        });
-
-        // We only care about single-user text-based chats
-        let filter = {};
-        filter[Tp.PROP_CHANNEL_CHANNEL_TYPE] = Tp.IFACE_CHANNEL_TYPE_TEXT;
-        filter[Tp.PROP_CHANNEL_TARGET_HANDLE_TYPE] = Tp.HandleType.CONTACT;
-
-        this.set_observer_recover(true);
-        this.add_observer_filter(filter);
-        this.add_approver_filter(filter);
-        this.add_handler_filter(filter);
-
-        // Allow other clients (such as Empathy) to preempt our channels if
-        // needed
-        this.set_delegated_channels_callback(
-            this._delegatedChannelsCb.bind(this));
-    }
-
-    vfunc_observe_channels(...args) {
-        let [account, conn, channels, dispatchOp_, requests_, context] = args;
-        let len = channels.length;
-        for (let i = 0; i < len; i++) {
-            let channel = channels[i];
-            let [targetHandle_, targetHandleType] = channel.get_handle();
-
-            if (channel.get_invalidated())
-                continue;
-
-            /* Only observe contact text channels */
-            if (!(channel instanceof Tp.TextChannel) ||
-               targetHandleType !== Tp.HandleType.CONTACT)
-                continue;
-
-            this._createChatSource(account, conn, channel, channel.get_target_contact());
-        }
-
-        context.accept();
-    }
-
-    _createChatSource(account, conn, channel, contact) {
-        if (this._chatSources[channel.get_object_path()])
-            return;
-
-        let source = new ChatSource(account, conn, channel, contact, this);
-
-        this._chatSources[channel.get_object_path()] = source;
-        source.connect('destroy', () => {
-            delete this._chatSources[channel.get_object_path()];
-        });
-    }
-
-    vfunc_handle_channels(...args) {
-        let [account, conn, channels, requests_, userActionTime_, context] = args;
-        this._handlingChannels(account, conn, channels, true);
-        context.accept();
-    }
-
-    _handlingChannels(account, conn, channels, notify) {
-        let len = channels.length;
-        for (let i = 0; i < len; i++) {
-            let channel = channels[i];
-
-            // We can only handle text channel, so close any other channel
-            if (!(channel instanceof Tp.TextChannel)) {
-                channel.close_async();
-                continue;
-            }
-
-            if (channel.get_invalidated())
-                continue;
-
-            // 'notify' will be true when coming from an actual HandleChannels
-            // call, and not when from a successful Claim call. The point is
-            // we don't want to notify for a channel we just claimed which
-            // has no new messages (for example, a new channel which only has
-            // a delivery notification). We rely on _displayPendingMessages()
-            // and _messageReceived() to notify for new messages.
-
-            // But we should still notify from HandleChannels because the
-            // Telepathy spec states that handlers must foreground channels
-            // in HandleChannels calls which are already being handled.
-
-            if (notify && this.is_handling_channel(channel)) {
-                // We are already handling the channel, display the source
-                let source = this._chatSources[channel.get_object_path()];
-                if (source)
-                    source.showNotification();
-            }
-        }
-    }
-
-    vfunc_add_dispatch_operation(...args) {
-        let [account, conn, channels, dispatchOp, context] = args;
-        let channel = channels[0];
-        let chanType = channel.get_channel_type();
-
-        if (channel.get_invalidated()) {
-            context.fail(new Tp.Error({
-                code: Tp.Error.INVALID_ARGUMENT,
-                message: 'Channel is invalidated',
-            }));
-            return;
-        }
-
-        if (chanType === Tp.IFACE_CHANNEL_TYPE_TEXT) {
-            this._approveTextChannel(account, conn, channel, dispatchOp, context);
-        } else {
-            context.fail(new Tp.Error({
-                code: Tp.Error.INVALID_ARGUMENT,
-                message: 'Unsupported channel type',
-            }));
-        }
-    }
-
-    async _approveTextChannel(account, conn, channel, dispatchOp, context) {
-        let [targetHandle_, targetHandleType] = channel.get_handle();
-
-        if (targetHandleType !== Tp.HandleType.CONTACT) {
-            context.fail(new Tp.Error({
-                code: Tp.Error.INVALID_ARGUMENT,
-                message: 'Unsupported handle type',
-            }));
-            return;
-        }
-
-        context.accept();
-
-        // Approve private text channels right away as we are going to handle it
-        try {
-            await dispatchOp.claim_with_async(this);
-            this._handlingChannels(account, conn, [channel], false);
-        } catch (err) {
-            log(`Failed to claim channel: ${err}`);
-        }
-    }
-
-    _delegatedChannelsCb(_client, _channels) {
-        // Nothing to do as we don't make a distinction between observed and
-        // handled channels.
-    }
-}) : null;
-
-const ChatSource = HAVE_TP ? GObject.registerClass(
-class ChatSource extends MessageTray.Source {
-    constructor(account, conn, channel, contact, client) {
-        const appId = account.protocol_name === 'irc'
-            ? 'org.gnome.Polari'
-            : 'empathy';
-        const policy =
-            new MessageTray.NotificationApplicationPolicy(appId);
-
-        super({policy});
-
-        this._account = account;
-        this._contact = contact;
-        this._client = client;
-
-        this._pendingMessages = [];
-
-        this._conn = conn;
-        this._channel = channel;
-
-        this._notifyTimeoutId = 0;
-
-        this._presence = contact.get_presence_type();
-
-        this._channel.connectObject(
-            'invalidated', this._channelClosed.bind(this),
-            'message-sent', this._messageSent.bind(this),
-            'message-received', this._messageReceived.bind(this),
-            'pending-message-removed', this._pendingRemoved.bind(this), this);
-
-        this._contact.connectObject(
-            'notify::alias', this._updateAlias.bind(this),
-            'notify::avatar-file', this._updateAvatarIcon.bind(this), this);
-
-        this._updateAlias();
-        this._updateAvatarIcon();
-        // Add ourselves as a source.
-        Main.messageTray.add(this);
-
-        this._getLogMessages();
-    }
-
-    _ensureNotification() {
-        if (this._notification)
-            return;
-
-        this._notification = new ChatNotification(this);
-        this._notification.connectObject(
-            'activated', this.open.bind(this),
-            'destroy', () => (this._notification = null),
-            'updated', () => {
-                if (this._banner && this._banner.expanded)
-                    this._ackMessages();
-            }, this);
-        this.pushNotification(this._notification);
-    }
-
-    createBanner() {
-        this._banner = new ChatNotificationBanner(this._notification);
-
-        // We ack messages when the user expands the new notification
-        this._banner.connectObject(
-            'expanded', this._ackMessages.bind(this),
-            'destroy', () => (this._banner = null), this);
-
-        return this._banner;
-    }
-
-    _updateAlias() {
-        let oldAlias = this.title;
-        let newAlias = this._contact.get_alias();
-
-        if (oldAlias === newAlias)
-            return;
-
-        this.title = newAlias;
-        if (this._notification)
-            this._notification.appendAliasChange(oldAlias, newAlias);
-    }
-
-    _updateAvatarIcon() {
-        let file = this._contact.get_avatar_file();
-        if (file) {
-            if (this.icon instanceof Gio.FileIcon)
-                this.icon.file = file;
-            else
-                this.icon = new Gio.FileIcon({file});
-        } else if (!(this.icon instanceof Gio.ThemedIcon)) {
-            this.iconName = 'avatar-default';
-        }
-
-        if (this._notification && this.icon !== this._notification.gicon) {
-            this._notification.update(
-                this._notification.title,
-                this._notification.bannerBodyText,
-                {gicon: this.icon});
-        }
-    }
-
-    open() {
-        Main.overview.hide();
-        Main.panel.closeCalendar();
-
-        if (this._client.is_handling_channel(this._channel)) {
-            // We are handling the channel, try to pass it to Empathy or Polari
-            // (depending on the channel type)
-            // We don't check if either app is available - mission control will
-            // fallback to something else if activation fails
-
-            let target;
-            if (this._channel.connection.protocol_name === 'irc')
-                target = 'org.freedesktop.Telepathy.Client.Polari';
-            else
-                target = 'org.freedesktop.Telepathy.Client.Empathy.Chat';
-            this._client.delegate_channels_async([this._channel], global.get_current_time(), target, null);
-        } else {
-            // We are not the handler, just ask to present the channel
-            let dbus = Tp.DBusDaemon.dup();
-            let cd = Tp.ChannelDispatcher.new(dbus);
-
-            cd.present_channel_async(this._channel, global.get_current_time(), null);
-        }
-    }
-
-    async _getLogMessages() {
-        let logManager = Tpl.LogManager.dup_singleton();
-        let entity = Tpl.Entity.new_from_tp_contact(this._contact, Tpl.EntityType.CONTACT);
-
-        const [events] = await logManager.get_filtered_events_async(
-            this._account, entity,
-            Tpl.EventTypeMask.TEXT, SCROLLBACK_HISTORY_LINES,
-            null);
-
-        let logMessages = events.map(e => ChatMessage.newFromTplTextEvent(e));
-        this._ensureNotification();
-
-        let pendingTpMessages = this._channel.get_pending_messages();
-        let pendingMessages = [];
-
-        for (let i = 0; i < pendingTpMessages.length; i++) {
-            let message = pendingTpMessages[i];
-
-            if (message.get_message_type() === Tp.ChannelTextMessageType.DELIVERY_REPORT)
-                continue;
-
-            pendingMessages.push(ChatMessage.newFromTpMessage(message,
-                NotificationDirection.RECEIVED));
-
-            this._pendingMessages.push(message);
-        }
-
-        this.countUpdated();
-
-        let showTimestamp = false;
-
-        for (let i = 0; i < logMessages.length; i++) {
-            let logMessage = logMessages[i];
-            let isPending = false;
-
-            // Skip any log messages that are also in pendingMessages
-            for (let j = 0; j < pendingMessages.length; j++) {
-                let pending = pendingMessages[j];
-                if (logMessage.timestamp === pending.timestamp && logMessage.text === pending.text) {
-                    isPending = true;
-                    break;
-                }
-            }
-
-            if (!isPending) {
-                showTimestamp = true;
-                this._notification.appendMessage(logMessage, true, ['chat-log-message']);
-            }
-        }
-
-        if (showTimestamp)
-            this._notification.appendTimestamp();
-
-        for (let i = 0; i < pendingMessages.length; i++)
-            this._notification.appendMessage(pendingMessages[i], true);
-
-        if (pendingMessages.length > 0)
-            this.showNotification();
-    }
-
-    destroy(reason) {
-        if (this._client.is_handling_channel(this._channel)) {
-            this._ackMessages();
-            // The chat box has been destroyed so it can't
-            // handle the channel any more.
-            this._channel.close_async();
-        } else {
-            // Don't indicate any unread messages when the notification
-            // that represents them has been destroyed.
-            this._pendingMessages = [];
-            this.countUpdated();
-        }
-
-        // Keep source alive while the channel is open
-        if (reason !== MessageTray.NotificationDestroyedReason.SOURCE_CLOSED)
-            return;
-
-        if (this._destroyed)
-            return;
-
-        this._destroyed = true;
-        this._channel.disconnectObject(this);
-        this._contact.disconnectObject(this);
-
-        super.destroy(reason);
-    }
-
-    _channelClosed() {
-        this.destroy(MessageTray.NotificationDestroyedReason.SOURCE_CLOSED);
-    }
-
-    /* All messages are new messages for Telepathy sources */
-    get count() {
-        return this._pendingMessages.length;
-    }
-
-    get unseenCount() {
-        return this.count;
-    }
-
-    get countVisible() {
-        return this.count > 0;
-    }
-
-    _messageReceived(channel, message) {
-        if (message.get_message_type() === Tp.ChannelTextMessageType.DELIVERY_REPORT)
-            return;
-
-        this._ensureNotification();
-        this._pendingMessages.push(message);
-        this.countUpdated();
-
-        message = ChatMessage.newFromTpMessage(message,
-            NotificationDirection.RECEIVED);
-        this._notification.appendMessage(message);
-
-        // Wait a bit before notifying for the received message, a handler
-        // could ack it in the meantime.
-        if (this._notifyTimeoutId !== 0)
-            GLib.source_remove(this._notifyTimeoutId);
-        this._notifyTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 500,
-            this._notifyTimeout.bind(this));
-        GLib.Source.set_name_by_id(this._notifyTimeoutId, '[gnome-shell] this._notifyTimeout');
-    }
-
-    _notifyTimeout() {
-        if (this._pendingMessages.length !== 0)
-            this.showNotification();
-
-        this._notifyTimeoutId = 0;
-
-        return GLib.SOURCE_REMOVE;
-    }
-
-    // This is called for both messages we send from
-    // our client and other clients as well.
-    _messageSent(channel, message, _flags, _token) {
-        this._ensureNotification();
-        message = ChatMessage.newFromTpMessage(message,
-            NotificationDirection.SENT);
-        this._notification.appendMessage(message);
-    }
-
-    showNotification() {
-        super.showNotification(this._notification);
-    }
-
-    respond(text) {
-        let type;
-        if (text.slice(0, 4) === '/me ') {
-            type = Tp.ChannelTextMessageType.ACTION;
-            text = text.slice(4);
-        } else {
-            type = Tp.ChannelTextMessageType.NORMAL;
-        }
-
-        let msg = Tp.ClientMessage.new_text(type, text);
-        this._channel.send_message_async(msg, 0);
-    }
-
-    setChatState(state) {
-        // We don't want to send COMPOSING every time a letter is typed into
-        // the entry. We send the state only when it changes. Telepathy/Empathy
-        // might change it behind our back if the user is using both
-        // gnome-shell's entry and the Empathy conversation window. We could
-        // keep track of it with the ChatStateChanged signal but it is good
-        // enough right now.
-        if (state !== this._chatState) {
-            this._chatState = state;
-            this._channel.set_chat_state_async(state, null);
-        }
-    }
-
-    _pendingRemoved(channel, message) {
-        let idx = this._pendingMessages.indexOf(message);
-
-        if (idx >= 0) {
-            this._pendingMessages.splice(idx, 1);
-            this.countUpdated();
-        }
-
-        if (this._pendingMessages.length === 0 &&
-            this._banner && !this._banner.expanded)
-            this._banner.hide();
-    }
-
-    _ackMessages() {
-        // Don't clear our messages here, tp-glib will send a
-        // 'pending-message-removed' for each one.
-        this._channel.ack_all_pending_messages_async(null);
-    }
-}) : null;
-
-const ChatNotificationMessage = HAVE_TP ? GObject.registerClass(
-class ChatNotificationMessage extends GObject.Object {
-    _init(props = {}) {
-        super._init();
-        this.set(props);
-    }
-}) : null;
-
-const ChatNotification = HAVE_TP ? GObject.registerClass({
-    Signals: {
-        'message-removed': {param_types: [ChatNotificationMessage.$gtype]},
-        'message-added': {param_types: [ChatNotificationMessage.$gtype]},
-        'timestamp-changed': {param_types: [ChatNotificationMessage.$gtype]},
-    },
-}, class ChatNotification extends MessageTray.Notification {
-    constructor(source) {
-        super(source, source.title, null, null);
-        this.setUrgency(MessageTray.Urgency.HIGH);
-        this.setResident(true);
-
-        this.messages = [];
-        this._timestampTimeoutId = 0;
-    }
-
-    destroy(reason) {
-        if (this._timestampTimeoutId)
-            GLib.source_remove(this._timestampTimeoutId);
-        this._timestampTimeoutId = 0;
-        super.destroy(reason);
-    }
-
-    /**
-     * @param {object} message - An object with the properties
-     *   {string} message.text - the body of the message,
-     *   {Tp.ChannelTextMessageType} message.messageType - the type
-     *   {string} message.sender - the name of the sender,
-     *   {number} message.timestamp - the time the message was sent
-     *   {NotificationDirection} message.direction - a #NotificationDirection
-     *
-     * @param {bool} noTimestamp - Whether to add a timestamp. If %true,
-     *   no timestamp will be added, regardless of the difference since
-     *   the last timestamp
-     */
-    appendMessage(message, noTimestamp) {
-        let messageBody = GLib.markup_escape_text(message.text, -1);
-        let styles = [message.direction];
-
-        if (message.messageType === Tp.ChannelTextMessageType.ACTION) {
-            let senderAlias = GLib.markup_escape_text(message.sender, -1);
-            messageBody = `<i>${senderAlias}</i> ${messageBody}`;
-            styles.push('chat-action');
-        }
-
-        if (message.direction === NotificationDirection.RECEIVED) {
-            this.update(this.source.title, messageBody, {
-                datetime: GLib.DateTime.new_from_unix_local(message.timestamp),
-                bannerMarkup: true,
-            });
-        }
-
-        let group = message.direction === NotificationDirection.RECEIVED
-            ? 'received' : 'sent';
-
-        this._append({
-            body: messageBody,
-            group,
-            styles,
-            timestamp: message.timestamp,
-            noTimestamp,
-        });
-    }
-
-    _filterMessages() {
-        if (this.messages.length < 1)
-            return;
-
-        let lastMessageTime = this.messages[0].timestamp;
-        let currentTime = Date.now() / 1000;
-
-        // Keep the scrollback from growing too long. If the most
-        // recent message (before the one we just added) is within
-        // SCROLLBACK_RECENT_TIME, we will keep
-        // SCROLLBACK_RECENT_LENGTH previous messages. Otherwise
-        // we'll keep SCROLLBACK_IDLE_LENGTH messages.
-
-        let maxLength = lastMessageTime < currentTime - SCROLLBACK_RECENT_TIME
-            ? SCROLLBACK_IDLE_LENGTH : SCROLLBACK_RECENT_LENGTH;
-
-        let filteredHistory = this.messages.filter(item => item.realMessage);
-        if (filteredHistory.length > maxLength) {
-            let lastMessageToKeep = filteredHistory[maxLength];
-            let expired = this.messages.splice(this.messages.indexOf(lastMessageToKeep));
-            for (let i = 0; i < expired.length; i++)
-                this.emit('message-removed', expired[i]);
-        }
-    }
-
-    /**
-     * @param {object} props - An object with the properties:
-     *  {string} props.body - The text of the message.
-     *  {string} props.group - The group of the message, one of:
-     *         'received', 'sent', 'meta'.
-     *  {string[]} props.styles - Style class names for the message to have.
-     *  {number} props.timestamp - The timestamp of the message.
-     *  {bool} props.noTimestamp - suppress timestamp signal?
-     */
-    _append(props) {
-        let currentTime = Date.now() / 1000;
-        props = Params.parse(props, {
-            body: null,
-            group: null,
-            styles: [],
-            timestamp: currentTime,
-            noTimestamp: false,
-        });
-        const {noTimestamp} = props;
-        delete props.noTimestamp;
-
-        // Reset the old message timeout
-        if (this._timestampTimeoutId)
-            GLib.source_remove(this._timestampTimeoutId);
-        this._timestampTimeoutId = 0;
-
-        let message = new ChatNotificationMessage({
-            realMessage: props.group !== 'meta',
-            showTimestamp: false,
-            ...props,
-        });
-
-        this.messages.unshift(message);
-        this.emit('message-added', message);
-
-        if (!noTimestamp) {
-            let timestamp = props.timestamp;
-            if (timestamp < currentTime - SCROLLBACK_IMMEDIATE_TIME) {
-                this.appendTimestamp();
-            } else {
-                // Schedule a new timestamp in SCROLLBACK_IMMEDIATE_TIME
-                // from the timestamp of the message.
-                this._timestampTimeoutId = GLib.timeout_add_seconds(
-                    GLib.PRIORITY_DEFAULT,
-                    SCROLLBACK_IMMEDIATE_TIME - (currentTime - timestamp),
-                    this.appendTimestamp.bind(this));
-                GLib.Source.set_name_by_id(this._timestampTimeoutId, '[gnome-shell] this.appendTimestamp');
-            }
-        }
-
-        this._filterMessages();
-    }
-
-    appendTimestamp() {
-        this._timestampTimeoutId = 0;
-
-        this.messages[0].showTimestamp = true;
-        this.emit('timestamp-changed', this.messages[0]);
-
-        this._filterMessages();
-
-        return GLib.SOURCE_REMOVE;
-    }
-
-    appendAliasChange(oldAlias, newAlias) {
-        oldAlias = GLib.markup_escape_text(oldAlias, -1);
-        newAlias = GLib.markup_escape_text(newAlias, -1);
-
-        /* Translators: this is the other person changing their old IM name to their new
-           IM name. */
-        const message = `<i>${
-            _('%s is now known as %s').format(oldAlias, newAlias)}</i>`;
-
-        this._append({
-            body: message,
-            group: 'meta',
-            styles: ['chat-meta-message'],
-        });
-
-        this._filterMessages();
-    }
-}) : null;
-
-const ChatLineBox = GObject.registerClass(
-class ChatLineBox extends St.BoxLayout {
-    vfunc_get_preferred_height(forWidth) {
-        let [, natHeight] = super.vfunc_get_preferred_height(forWidth);
-        return [natHeight, natHeight];
-    }
-});
-
-const ChatNotificationBanner = GObject.registerClass(
-class ChatNotificationBanner extends MessageTray.NotificationBanner {
-    _init(notification) {
-        super._init(notification);
-
-        this._responseEntry = new St.Entry({
-            style_class: 'chat-response',
-            x_expand: true,
-            can_focus: true,
-        });
-        this._responseEntry.clutter_text.connect('activate', this._onEntryActivated.bind(this));
-        this._responseEntry.clutter_text.connect('text-changed', this._onEntryChanged.bind(this));
-        this.setActionArea(this._responseEntry);
-
-        this._responseEntry.clutter_text.connect('key-focus-in', () => {
-            this.focused = true;
-        });
-        this._responseEntry.clutter_text.connect('key-focus-out', () => {
-            this.focused = false;
-            this.emit('unfocused');
-        });
-
-        this._contentArea = new St.BoxLayout({
-            style_class: 'chat-body',
-            vertical: true,
-        });
-        this._scrollArea = new St.ScrollView({
-            style_class: 'chat-scrollview vfade',
-            visible: this.expanded,
-            child: this._contentArea,
-        });
-
-        this.setExpandedBody(this._scrollArea);
-        this.setExpandedLines(CHAT_EXPAND_LINES);
-
-        this._lastGroup = null;
-
-        // Keep track of the bottom position for the current adjustment and
-        // force a scroll to the bottom if things change while we were at the
-        // bottom
-        this._oldMaxScrollValue = this._scrollArea.vadjustment.value;
-        this._scrollArea.vadjustment.connect('changed', adjustment => {
-            if (adjustment.value === this._oldMaxScrollValue)
-                this.scrollTo(St.Side.BOTTOM);
-            this._oldMaxScrollValue = Math.max(adjustment.lower, adjustment.upper - adjustment.page_size);
-        });
-
-        this._inputHistory = new History.HistoryManager({entry: this._responseEntry.clutter_text});
-
-        this._composingTimeoutId = 0;
-
-        this._messageActors = new Map();
-
-        this.notification.connectObject(
-            'timestamp-changed', (n, message) => this._updateTimestamp(message),
-            'message-added', (n, message) => this._addMessage(message),
-            'message-removed', (n, message) => {
-                let actor = this._messageActors.get(message);
-                if (this._messageActors.delete(message))
-                    actor.destroy();
-            }, this);
-
-        for (let i = this.notification.messages.length - 1; i >= 0; i--)
-            this._addMessage(this.notification.messages[i]);
-    }
-
-    scrollTo(side) {
-        let adjustment = this._scrollArea.vadjustment;
-        if (side === St.Side.TOP)
-            adjustment.value = adjustment.lower;
-        else if (side === St.Side.BOTTOM)
-            adjustment.value = adjustment.upper;
-    }
-
-    hide() {
-        this.emit('done-displaying');
-    }
-
-    _addMessage(message) {
-        let body = new MessageList.URLHighlighter(message.body, true, true);
-
-        let styles = message.styles;
-        for (let i = 0; i < styles.length; i++)
-            body.add_style_class_name(styles[i]);
-
-        let group = message.group;
-        if (group !== this._lastGroup) {
-            this._lastGroup = group;
-            body.add_style_class_name('chat-new-group');
-        }
-
-        let lineBox = new ChatLineBox();
-        lineBox.add_child(body);
-        this._contentArea.add_child(lineBox);
-        this._messageActors.set(message, lineBox);
-
-        this._updateTimestamp(message);
-    }
-
-    _updateTimestamp(message) {
-        let actor = this._messageActors.get(message);
-        if (!actor)
-            return;
-
-        while (actor.get_n_children() > 1)
-            actor.get_child_at_index(1).destroy();
-
-        if (message.showTimestamp) {
-            let lastMessageTime = message.timestamp;
-            let lastMessageDate = new Date(lastMessageTime * 1000);
-
-            let timeLabel = Util.createTimeLabel(lastMessageDate);
-            timeLabel.style_class = 'chat-meta-message';
-            timeLabel.x_expand = timeLabel.y_expand = true;
-            timeLabel.x_align = timeLabel.y_align = Clutter.ActorAlign.END;
-
-            actor.add_child(timeLabel);
-        }
-    }
-
-    _onEntryActivated() {
-        let text = this._responseEntry.get_text();
-        if (text === '')
-            return;
-
-        this._inputHistory.addItem(text);
-
-        // Telepathy sends out the Sent signal for us.
-        // see Source._messageSent
-        this._responseEntry.set_text('');
-        this.notification.source.respond(text);
-    }
-
-    _composingStopTimeout() {
-        this._composingTimeoutId = 0;
-
-        this.notification.source.setChatState(Tp.ChannelChatState.PAUSED);
-
-        return GLib.SOURCE_REMOVE;
-    }
-
-    _onEntryChanged() {
-        let text = this._responseEntry.get_text();
-
-        // If we're typing, we want to send COMPOSING.
-        // If we empty the entry, we want to send ACTIVE.
-        // If we've stopped typing for COMPOSING_STOP_TIMEOUT
-        //    seconds, we want to send PAUSED.
-
-        // Remove composing timeout.
-        if (this._composingTimeoutId > 0) {
-            GLib.source_remove(this._composingTimeoutId);
-            this._composingTimeoutId = 0;
-        }
-
-        if (text !== '') {
-            this.notification.source.setChatState(Tp.ChannelChatState.COMPOSING);
-
-            this._composingTimeoutId = GLib.timeout_add_seconds(
-                GLib.PRIORITY_DEFAULT,
-                COMPOSING_STOP_TIMEOUT,
-                this._composingStopTimeout.bind(this));
-            GLib.Source.set_name_by_id(this._composingTimeoutId, '[gnome-shell] this._composingStopTimeout');
-        } else {
-            this.notification.source.setChatState(Tp.ChannelChatState.ACTIVE);
-        }
-    }
-});
-
-export const Component = TelepathyComponent;
index 163d3eab52c07dd848fd4a9371fbb6ece8526104..8e1d1ed1013c6b15ebf02fbc2529c5c1478b1364 100644 (file)
@@ -59,8 +59,7 @@ export const NotificationDestroyedReason = {
 
 // Message tray has its custom Urgency enumeration. LOW, NORMAL and CRITICAL
 // urgency values map to the corresponding values for the notifications received
-// through the notification daemon. HIGH urgency value is used for chats received
-// through the Telepathy client.
+// through the notification daemon.
 /** @enum {number} */
 export const Urgency = {
     LOW: 0,
@@ -529,7 +528,6 @@ SignalTracker.registerDestroyableType(Notification);
 export const NotificationBanner = GObject.registerClass({
     Signals: {
         'done-displaying': {},
-        'unfocused': {},
     },
 }, class NotificationBanner extends Calendar.NotificationMessage {
     _init(notification) {
@@ -1125,7 +1123,6 @@ export const MessageTray = GObject.registerClass({
             let expired = (this._userActiveWhileNotificationShown &&
                            this._notificationTimeoutId === 0 &&
                            this._notification.urgency !== Urgency.CRITICAL &&
-                           !this._banner.focused &&
                            !this._pointerInNotification) || this._notificationExpired;
             let mustClose = this._notificationRemoved || !hasNotifications || expired;
 
@@ -1166,9 +1163,7 @@ export const MessageTray = GObject.registerClass({
         }
 
         this._banner = this._notification.createBanner();
-        this._banner.connectObject(
-            'done-displaying', this._escapeTray.bind(this),
-            'unfocused', () => this._updateState(), this);
+        this._banner.connectObject('done-displaying', this._escapeTray.bind(this), this);
 
         this._bannerBin.add_child(this._banner);
 
index 9c80532b6c9e32063f412c2737998f9e69aba471..895b507e113c79df45342fea0d6ed0d71d3a2976 100644 (file)
@@ -13,7 +13,7 @@ import * as Config from '../misc/config.js';
 const DEFAULT_MODE = 'restrictive';
 
 const USER_SESSION_COMPONENTS = [
-    'polkitAgent', 'telepathyClient', 'keyring',
+    'polkitAgent', 'keyring',
     'autorunManager', 'automountManager',
 ];
 
@@ -69,7 +69,7 @@ const _modes = {
     'unlock-dialog': {
         isLocked: true,
         unlockDialog: undefined,
-        components: ['polkitAgent', 'telepathyClient'],
+        components: ['polkitAgent'],
         panel: {
             left: [],
             center: [],
index 35cb77c6969631f336f0c989ea3774d06e1a29b7..0a9aa2f8dce34108f831ae74d0b3e05c6db6ac89 100644 (file)
@@ -28,7 +28,6 @@ js/ui/components/autorunManager.js
 js/ui/components/keyring.js
 js/ui/components/networkAgent.js
 js/ui/components/polkitAgent.js
-js/ui/components/telepathyClient.js
 js/ui/ctrlAltTab.js
 js/ui/dash.js
 js/ui/dateMenu.js